package com.nx.arch.addon.lock.lock;

import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;

import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;

import com.nx.arch.addon.lock.NxLock;
import com.nx.arch.addon.lock.exception.LockException;

/**
 * @类名称 BaseLock.java
 * @类描述 锁基类
 * @作者  庄梦蝶殇 linhuaichuan@naixuejiaoyu.com
 * @创建时间 2020年3月28日 下午3:40:24
 * @版本 1.0.0
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.0.0 		庄梦蝶殇 	2020年3月28日             
 *     ----------------------------------------------
 * </pre>
 */
public abstract class BaseLock extends NxLock {
    
    /**
     * 默认过期时间，单位s
     */
    protected final static int DEFAULT_SENCOND = 10;
    
    /**
     * 默认缓存值
     */
    protected final static String DEF_VAL = "1";
    
    /**
     * 活跃重入锁
     */
    protected static final ThreadLocal<HashSet<String>> holdLocks = new ThreadLocal<HashSet<String>>() {
        @Override
        protected HashSet<String> initialValue() {
            return new HashSet<String>();
        }
    };
    
    /**
     * 锁名
     */
    protected String key;
    
    /**
     * 锁值
     */
    protected String value;
    
    /**
     * 过期时间
     */
    protected Integer ttl;
    
    /**
     * 是否支持锁重入
     */
    protected boolean reentrant;
    
    /**
     * 是否已经持有锁
     */
    protected final AtomicBoolean hold = new AtomicBoolean(false);
    
    public BaseLock(String key, String value, boolean reentrant) {
        this.key = key;
        this.value = value;
        this.ttl = DEFAULT_SENCOND;
        this.reentrant = reentrant;
    }
    
    /**
     * @方法名称 acquire
     * @功能描述  获取锁，如果没得到，不阻塞
     * @param ttl 锁过期时间
     * @return true-获取锁，false-未获得锁
     * @throws LockException 锁异常
     */    
    @Override
    public boolean acquire(int ttl)
        throws LockException {
        if (getClient() == null || StringUtils.isEmpty(key)) {
            // 空锁
            return false;
        } else if (reentrant && holdLocks.get().contains(key)) {
            // 重入锁
            return true;
        }
        this.ttl = (ttl <= 0 ? DEFAULT_SENCOND : ttl);
        StopWatch watcher = new StopWatch();
        boolean isAcquire = lock();
        if (watcher != null && watcher.isRunning()) {
            watcher.stop();
            // int cost = (int) watcher.getTotalTimeMillis();
            // 上报监控
            // NxMonitor.avg(31, cost, 1);
            // NxMonitor.max(33, cost);
        }
        return isAcquire;
    }
    
    /**
     * @方法名称 acquire
     * @功能描述   获取锁，直到超时
     * @param ttl 锁过期时间
     * @param interval 重试间隔时间
     * @param retryCount 重试次数
     * @return true-获取锁，false-未获得锁
     * @throws LockException 锁异常
     */    
    @Override
    public boolean acquire(int ttl, long interval, int retryCount)
        throws LockException {
        if (getClient() == null || StringUtils.isEmpty(key)) {
            // 空锁
            return false;
        } else if (reentrant && holdLocks.get().contains(key)) {
            // 重入锁
            return true;
        }
        this.ttl = (ttl <= 0 ? DEFAULT_SENCOND : ttl);
        try {
            if (!lock()) {
                // 重试抢锁
                if (retryCount > 0) {
                    Thread.sleep((interval * 1000) <= 0 ? 1 : (interval * 1000));
                    return acquire(ttl, interval, retryCount - 1);
                }
            }
        } catch (Exception e) {
            if (retryCount > 0) {
                try {
                    Thread.sleep((interval * 1000) <= 0 ? 1 : (interval * 1000));
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                return acquire(ttl, interval, retryCount - 1);
            }
        }
        return hold.get();
    }
    
    @Override
    public void close()
        throws LockException {
        try {
            if (hold.get()) {
                StopWatch watcher = new StopWatch();
                release();
                if (watcher != null && watcher.isRunning()) {
                    watcher.stop();
                    // int cost = (int) watcher.getTotalTimeMillis();
                    // 上报监控
                    // NxMonitor.avg(32, cost, 1);
                }
            }
        } catch (LockException ex) {
            throw ex;
        }
    }
    
    /**
     * @方法名称 lock
     * @功能描述 抢锁
     * @return true-获取锁，false-未获得锁
     * @throws LockException 锁异常
     */
    protected abstract boolean lock()
        throws LockException;
    
    /**
     * @方法名称 release
     * @功能描述 <pre>释放锁</pre>
     * @throws LockException 锁异常
     */    
    @Override
    public abstract void release()
        throws LockException;
    
    /**
     * @方法名称 getClient
     * @功能描述 <pre>获取方案客户端</pre>
     */    
    protected abstract Object getClient();
}
